#!/usr/bin/env python
# -*- encoding: utf-8 -*-
'''
@NAME          : alioss.py
@TIME          : 2022/10/28 14:41:52
@AUTHOR        : chenlip
@VERSION       : 0.0.x
@DESCRIPTION   : 用于操作 阿里云 SSO 存储
'''

import os, json, datetime, requests
import oss2
import oss2.exceptions

from conf.config import Config
from common.logutil import log

import urllib3
from urllib.parse import quote, unquote

class AliOSSAct:
    # 阿里SSO图床的操作类

    def __init__(self) -> None:
        '''
            直接从配置文件中获取Ali OSS的服务器和登录相关信息;
        '''
        self.cf = Config()
        aliossserv = self.cf.ALIYUN_OSS["endpoint"]
        __AccessKeyID = self.cf.ALIYUN_OSS["AccessKeyID"]
        __AccessKeySecret = self.cf.ALIYUN_OSS["AccessKeySecret"]

        self._alissourl = "https://" + aliossserv
        self._bucket_name = self.cf.ALIYUN_OSS["bucket_name"]
        self._alissoblog = self.cf.ALIYUN_OSS["blogimgurl"] + self.cf.CURYEAR + "/"
        self._coverurl = self.cf.ALIYUN_OSS["coveimgurl"] + self.cf.CURYEAR + "/"
        
        # 初始化alisso客户端
        __auth = oss2.Auth(__AccessKeyID, __AccessKeySecret)
        self._ac = oss2.Bucket(__auth, aliossserv, self._bucket_name)

        log.info("连接 ali oss server ok !" + self._alissourl)

    def uploadCoverFile(self, fpath:str, pictype:str="") :
        '''
            上传文件到固定的位置, 默认：/blog/bookcover; 可以在配置文件中配置
            :Args: 
                - fpath, 文件的本地路径
                - pictype, 图片的类型目录, 默认为空,可选: imgurl(爬虫获取到的封面), small(生成的缩略图), imgepub(epub封面)
            :Return: 上传成功返回上传文件的图片格式地址, 否则返回"nourl"
        '''
        covmd_url = "nourl"
        acb = self._ac
        bucket_name = self._bucket_name
        if (pictype != ""):
            coverpath = self._coverurl + pictype + "/" # 图片的类型目录
        else:
            coverpath = self._coverurl + "/" # halo系统自用的目录, 
        coverpath = coverpath + self.cf.CURDAY + "/" # 当天的目录
        
        #obj_name = unquote(coverpath + os.path.basename(fpath), "utf-8")
        obj_name = coverpath + os.path.basename(fpath)

        try:
            # fobj = open(fpath,'rb')
            # acb.put_object(obj_name, fobj)
            acb.put_object_from_file(obj_name, fpath)
        except oss2.exceptions.RequestError as err:
            log.info("uploadFile: " + str(err))
        
        covmd_url = self._alissourl + "/" + self._bucket_name + "/" + obj_name
        log.info("上传图片成功: " + covmd_url)

        return covmd_url
    
    def uploadBgFile(self, fpath, pictype="51epub.com/mdimages/bg/pic/pc/bing", newfn=None) :
        '''
            上传当天的背景文件到固定的位置, 默认：/bg/pic/pc/ + 当天的日期; 
            :Args: 
                - fpath, 文件的本地路径
                - pictype, 图片的类型目录, 默认为空,可选: /bg/pic/pc(pc背景图片), /bg/pic/mobile(手机背景), /bg/video(视频背景)
                - newfn, 上传是否改用新的文件名, 默认为None, 如果不为None, 则会更新文件名

            :Return: 上传成功返回上传文件的图片格式地址, 否则返回"nobg"
        '''
        bg_url = "nobg"
        acb = self._ac
        bucket_name = self._bucket_name
        if (pictype != ""):
            bgpath = pictype + "/" # 图片的类型目录
        else:
            bgpath = "/" # 系统自用的目录, 

        #bgpath = bgpath + dy.curDay + "/" # 当天的目录
        
        obj_name = bgpath + os.path.basename(fpath)

        try:
            # fobj = open(fpath,'rb')
            # acb.put_object(obj_name, fobj)
            acb.put_object_from_file(obj_name, fpath)

            log.info("acb  上传图片成功: " + obj_name +"###"+ fpath)
        except oss2.exceptions.RequestError as err:
            log.info("uploadFile: 出现异常," + str(err))
        
        bg_url = self._alissourl + "/" + obj_name
        log.info("上传图片成功: " + bg_url)

        return bg_url
    
    def copyFile(self, src_obj:str, dst_obj="51epub.com/mdimages/bg/pic/pc/bing/7", newfn=None, dst_bucket=None) :
        '''
            将指定的文件复制到指定的bucket下
            :Args: 
                - dst_bucket, 新对象的存储桶名称
                - dst_obj, 新对象的存储路径
                - src_obj, 源对象的存储路径 存储桶名称+对象名称。例如: 51epub.com/mdimages/bg/pic/pc/bing/2022/2022-07-19.jpg
                - newfn, copy是否改用新的文件名, 默认为None, 如果不为None, 则会更新文件名
        '''
        acb = self._ac
        if (dst_bucket==None) : bucket_name = self._bucket_name

        if (newfn != None):
            _fn = newfn
        else:
            _fn = src_obj.split("/")[-1]

        _dst_obj = dst_obj + "/" + _fn
        _src_obj = src_obj.replace("\\\\", "\\")
        _dst_url = "NoURL"
        # 使用阿里云 oss 的copy功能
        try:
            acb.copy_object(bucket_name, _src_obj, _dst_obj)
            _dst_url = self._alissourl + "/" + bucket_name + "/" + _dst_obj
            log.info("aliOSS copyFile: " + _src_obj + " To! \n" + _dst_obj)
        except oss2.exceptions.RequestError as err:
            log.info("aliOSS copyFile 出现异常: " + str(err))

        return _dst_url
    
    # 处理异常
    def mvFNtoTarget(self, targetdir:str=None, deep:int=0):
        '''
            将制定目录下的文件移动到指定的目录下
            targetdir : mdblog/51epub.com/mdimages/blog/bookcover/2023/imgepub/2023-08-11/
            程序逻辑:
                1- 循环targetdir目录,递归找到该目录下所有子目录,如果找到文件jpg/jpeg/png
                2- 将jpg/jpeg/png文件移动到 targetdir下面
        '''
        if (targetdir != None):
            _tgd = targetdir
        else:
            _tgd = "51epub.com/mdimages/blog/bookcover/2023/imgepub/2023-08-11/"
        # 获取目标文件夹下的所有的文件夹
        # 列举fun文件夹下的文件与子文件夹名称，不列举子文件夹下的文件。
        deep += 1
        for obj in oss2.ObjectIterator(self._ac, prefix = _tgd, delimiter = '/', max_keys=200):
            
            # 通过is_prefix方法判断obj是否为文件夹。
            if obj.is_prefix():  # 判断obj为文件夹。
                print('obj.key directory: ' + ('- '* deep) + obj.key)
                # 显示子文件夹下面的文件
                _newdir = obj.key + "2023-08-12/"
                for obj_fn in oss2.ObjectIterator(self._ac, prefix=_newdir):
                    # print('##obj.key filename: ' + ('-- '* deep) + obj_fn.key)
                    _src_fn = obj_fn.key
                    _dst_fn = _tgd + str(obj_fn.key).split("/")[-1]

                    # 拷贝文件
                    self._ac.copy_object(self._bucket_name, _src_fn, _dst_fn)
                    print("OK--移动的目标:", _dst_fn +"\n")
                    
                    # 删除文件
                    # self._ac.delete_object(_src_fn)

